#pragma once
#include "gtest/gtest.h"
#include "DBManager/DBServiceFactory.h"
#include "DBManager/IService/Input/Subcase/ISubcaseService.h"
#include "DBManager/IService/Input/Coordinate/ICORD2RService.h"
#include "DBManager/IService/Input/Coordinate/ICORD2CService.h"
#include "DBManager/IService/Input/Coordinate/ICORD2SService.h"
#include "SGFem/Pre/Assembly/Assembly.h"
#include "SGFem/Pre/Assembly/CoordinateProcessor.h"
#include "../../Factory/ElementCalculatorFactory.h"
#include "../BushCalculator.h"

using SG::Algebra::Matrixd;
using SG::DataStructure::Common::Real;
using namespace SG::DataStructure::FEM;
using namespace SG::DBManager;
using SG::FEMSolver::AssemblyEigen;
using SG::FEMSolver::CoordinateProcessor;
using SG::FEMSolver::Element::ElementCalculatorFactory;
using SG::FEMSolver::Element::BushCalculator;

// ElementCalculatorFactory 是否正确创建 Bush 单元计算类
TEST (ElementCalculatorFactoryTest, CreateBushCalculator)
{
    ElementCalculatorFactory::Register (ElementTypes::ELETYPE_Bush, BushCalculator::Create);

    // Test data
    const auto calculatorPtr = ElementCalculatorFactory::Create (ElementTypes::ELETYPE_Bush);
    const auto bushCalculatorPtr = dynamic_cast<BushCalculator*> (calculatorPtr.get ());

    // Check
    ASSERT_TRUE (nullptr != bushCalculatorPtr);
}

extern std::shared_ptr<DBServiceFactory> DB_SERVICEFACTORY;
class BushCalculatorTest : public ::testing::Test
{
protected:
    static void SetUpTestSuite ()
    {
        DB_SERVICEFACTORY->ClearDatabase ();

        // 直角坐标系 100
        CORD2RData rectangularCoordSys{100, 0, {1.0, 2.0, 3.0}, {2.0, 4.0, 1.0}, {5.0, 1.0, 1.0}};
        DB_SERVICEFACTORY->get<ICORD2RService> ()->Add (rectangularCoordSys);

        // 直角坐标系 101
        rectangularCoordSys = {101, 0, {4.0, 3.0, 7.0}, {2.0, 6.0, 1.0}, {5.0, 1.0, 4.0}};
        DB_SERVICEFACTORY->get<ICORD2RService> ()->Add (rectangularCoordSys);

        // 柱坐标系 200
        CORD2CData cylindricalCoordSys{200, 0, 1.0, 2.0, 3.0, 2.0, 4.0, 1.0, 5.0, 1.0, 1.0};
        DB_SERVICEFACTORY->get<ICORD2CService> ()->Add (cylindricalCoordSys);

        // 柱坐标系 201
        cylindricalCoordSys = {201, 0, 4.0, 3.0, 7.0, 2.0, 6.0, 1.0, 5.0, 1.0, 4.0};
        DB_SERVICEFACTORY->get<ICORD2CService> ()->Add (cylindricalCoordSys);

        // 柱坐标系 202，额外测试用
        cylindricalCoordSys = {202, 0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 2.0, 1.0};
        DB_SERVICEFACTORY->get<ICORD2CService> ()->Add (cylindricalCoordSys);

        // 球坐标系 300
        CORD2SData sphericalCoordSys{300, 0, 1.0, 2.0, 3.0, 2.0, 4.0, 1.0, 5.0, 1.0, 1.0};
        DB_SERVICEFACTORY->get<ICORD2SService> ()->Add (sphericalCoordSys);

        // 球坐标系 301
        sphericalCoordSys = {301, 0, 4.0, 3.0, 7.0, 2.0, 6.0, 1.0, 5.0, 1.0, 4.0};
        DB_SERVICEFACTORY->get<ICORD2SService> ()->Add (sphericalCoordSys);

        // 生成节点排序
        auto& assembly = AssemblyEigen::GetInstance ();
        assembly.Clear ();
        Subcase subcase;
        assembly.Initialize (DB_SERVICEFACTORY, subcase, {1});

        // 计算坐标系原点和基矢量
        auto& coordProcessor = CoordinateProcessor::GetInstance ();
        coordProcessor.Clear ();
        coordProcessor.Initialize (DB_SERVICEFACTORY);
    }

    void SetUp () override
    {
        // 节点
        nodeSet.resize (2);
        nodeSet = {{6, 0, {10.0, 13.0, 15.0}, 0}, {8, 0, {15.0, 10.0, 5.0}, 0}};
        orienNode = {9, 0, {0.0, 1.0, 2.0}, 0};

        // 单元
        nEleNodes = 2;
        element.m_pId  = 2;
        element.m_g[0] = 6;
        element.m_g[1] = 8;
        isSpecifyEleCoordSys = true;

        // 单元属性
        property.m_id   = 2;
        property.m_K[0] = 1000.0;
        property.m_K[1] = 100.0;
        property.m_K[2] = 239.0;
        property.m_K[3] = 57.0;
        property.m_K[4] = 222.0;
        property.m_K[5] = 789.0;
        property.m_M    = 10.0;
    }

    std::vector<NodeData> nodeSet;
    NodeData orienNode;
    CBUSHData element;
    bool isSpecifyEleCoordSys;
    std::size_t nEleNodes;
    PBUSHData property;
};

// 局部坐标系单元刚度矩阵：单节点
TEST_F (BushCalculatorTest, ComputeLocalStiffnessWithOneGrid)
{
    // Input data
    nEleNodes = 1;

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd kgTest (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kgTest);

    // Target data
    Matrixd kgTarget (n, n);
    kgTarget (0, 0) = property.m_K[0];
    kgTarget (1, 1) = property.m_K[1];
    kgTarget (2, 2) = property.m_K[2];
    kgTarget (3, 3) = property.m_K[3];
    kgTarget (4, 4) = property.m_K[4];
    kgTarget (5, 5) = property.m_K[5];

    // Check
    ASSERT_TRUE (kgTarget == kgTest);
}

// 局部坐标系单元刚度矩阵：两节点
TEST_F (BushCalculatorTest, ComputeLocalStiffnessWithTwoGrids)
{
    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd kgTest (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kgTest);

    // Target data
    Matrixd kgTarget (n, n);
    kgTarget (0, 0)  = kgTarget (6, 6)   =  property.m_K[0];
    kgTarget (1, 1)  = kgTarget (7, 7)   =  property.m_K[1];
    kgTarget (2, 2)  = kgTarget (8, 8)   =  property.m_K[2];
    kgTarget (3, 3)  = kgTarget (9, 9)   =  property.m_K[3];
    kgTarget (4, 4)  = kgTarget (10, 10) =  property.m_K[4];
    kgTarget (5, 5)  = kgTarget (11, 11) =  property.m_K[5];
    kgTarget (0, 6)  = kgTarget (6, 0)   = -property.m_K[0];
    kgTarget (1, 7)  = kgTarget (7, 1)   = -property.m_K[1];
    kgTarget (2, 8)  = kgTarget (8, 2)   = -property.m_K[2];
    kgTarget (3, 9)  = kgTarget (9, 3)   = -property.m_K[3];
    kgTarget (4, 10) = kgTarget (10, 4)  = -property.m_K[4];
    kgTarget (5, 11) = kgTarget (11, 5)  = -property.m_K[5];

    // Check
    ASSERT_TRUE (kgTarget == kgTest);
}

// 非重合节点：CID>0(直角坐标系) + OCID=0(Si 偏置)
TEST_F (BushCalculatorTest, ComputeStiffnessWithTwoGridsRCIDgt0OCIDeq0)
{
    // Input data
    element.m_coordId = 100;
    element.m_oCId    = 0;
    element.m_s1      = 1.0;
    element.m_s2      = 2.0;
    element.m_s3      = 3.0;

    const Real* K{property.m_K};

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kgTest (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kgTest);
    kgTest = TEleOffset.Transpose () * kgTest * TEleOffset;

    // Target data
    const Matrixd kgTarget (n, n, {
     7.03679739E+02, -3.80875817E+02, -1.48535948E+02, -2.93661438E+03, -9.78098039E+03,  1.11683595E+04, -7.03679739E+02,  3.80875817E+02,  1.48535948E+02, -4.26535948E+02,  3.48686275E+03, -1.09616993E+04,
    -3.80875817E+02,  4.50013072E+02,  2.05751634E+01,  5.17383007E+03,  4.75568627E+03, -8.23975163E+03,  3.80875817E+02, -4.50013072E+02, -2.05751634E+01, -7.35424837E+02, -1.04980392E+03,  9.34718954E+03,
    -1.48535948E+02,  2.05751634E+01,  1.85307190E+02, -1.79147712E+03,  3.45019608E+03, -1.81907190E+03,  1.48535948E+02, -2.05751634E+01, -1.85307190E+02,  1.44130719E+03, -2.89137255E+03,  1.47633987E+03,
    -2.93661438E+03,  5.17383007E+03, -1.79147712E+03,  8.19693660E+04,  1.93175686E+04, -7.89716601E+04,  2.93661438E+03, -5.17383007E+03,  1.79147712E+03, -2.48566340E+04,  1.90059608E+04,  9.60309673E+04,
    -9.78098039E+03,  4.75568627E+03,  3.45019608E+03,  1.93175686E+04,  1.48844686E+05, -1.50659059E+05,  9.78098039E+03, -4.75568627E+03, -3.45019608E+03,  1.78887059E+04, -6.82858627E+04,  1.45094549E+05,
     1.11683595E+04, -8.23975163E+03, -1.81907190E+03, -7.89716601E+04, -1.50659059E+05,  1.97479405E+05, -1.11683595E+04,  8.23975163E+03,  1.81907190E+03,  2.03135948E+03,  4.80708235E+04, -2.05173085E+05,
    -7.03679739E+02,  3.80875817E+02,  1.48535948E+02,  2.93661438E+03,  9.78098039E+03, -1.11683595E+04,  7.03679739E+02, -3.80875817E+02, -1.48535948E+02,  4.26535948E+02, -3.48686275E+03,  1.09616993E+04,
     3.80875817E+02, -4.50013072E+02, -2.05751634E+01, -5.17383007E+03, -4.75568627E+03,  8.23975163E+03, -3.80875817E+02,  4.50013072E+02,  2.05751634E+01,  7.35424837E+02,  1.04980392E+03, -9.34718954E+03,
     1.48535948E+02, -2.05751634E+01, -1.85307190E+02,  1.79147712E+03, -3.45019608E+03,  1.81907190E+03, -1.48535948E+02,  2.05751634E+01,  1.85307190E+02, -1.44130719E+03,  2.89137255E+03, -1.47633987E+03,
    -4.26535948E+02, -7.35424837E+02,  1.44130719E+03, -2.48566340E+04,  1.78887059E+04,  2.03135948E+03,  4.26535948E+02,  7.35424837E+02, -1.44130719E+03,  1.31784641E+04, -2.08298824E+04, -6.98809150E+03,
     3.48686275E+03, -1.04980392E+03, -2.89137255E+03,  1.90059608E+04, -6.82858627E+04,  4.80708235E+04, -3.48686275E+03,  1.04980392E+03,  2.89137255E+03, -2.08298824E+04,  4.78740980E+04, -4.28592549E+04,
    -1.09616993E+04,  9.34718954E+03,  1.47633987E+03,  9.60309673E+04,  1.45094549E+05, -2.05173085E+05,  1.09616993E+04, -9.34718954E+03, -1.47633987E+03, -6.98809150E+03, -4.28592549E+04,  2.19023935E+05
    });

    // Check
    ASSERT_TRUE (kgTarget == kgTest);
}

// 非重合节点：朝向矢量 + OCID=-1(S 偏置)
TEST_F (BushCalculatorTest, ComputeStiffnessWithTwoGridsOrienVectorOCIDlt0)
{
    // Input data
    element.m_x1 = -10.0;
    element.m_x2 = -12.0;
    element.m_x3 = -13.0;

    const Real* K{property.m_K};

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kgTest (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kgTest);
    kgTest = TEleOffset.Transpose () * kgTest * TEleOffset;

    // Target data
    const Matrixd kgTarget (n, n, {
     2.89683331E+02, -1.45098439E+02, -3.11628803E+02, -2.58048990E+02, -6.69344650E+02,  7.17788999E+01, -2.89683331E+02,  1.45098439E+02,  3.11628803E+02, -2.58048990E+02, -6.69344650E+02,  7.17788999E+01,
    -1.45098439E+02,  2.50794775E+02,  1.52212348E+02,  1.02565535E+03,  3.44961324E+02,  4.09339278E+02,  1.45098439E+02, -2.50794775E+02, -1.52212348E+02,  1.02565535E+03,  3.44961324E+02,  4.09339278E+02,
    -3.11628803E+02,  1.52212348E+02,  7.98521894E+02, -4.36721100E+02, -4.38160722E+02, -8.69123335E+01,  3.11628803E+02, -1.52212348E+02, -7.98521894E+02, -4.36721100E+02, -4.38160722E+02, -8.69123335E+01,
    -2.58048990E+02,  1.02565535E+03, -4.36721100E+02,  6.06338939E+03,  2.21959929E+03,  2.33731491E+03,  2.58048990E+02, -1.02565535E+03,  4.36721100E+02,  5.50332742E+03,  2.54449612E+03,  2.01681487E+03,
    -6.69344650E+02,  3.44961324E+02, -4.38160722E+02,  2.21959929E+03,  5.02158078E+03, -3.79574592E+02,  6.69344650E+02, -3.44961324E+02,  4.38160722E+02,  2.54449612E+03,  3.86266933E+03,  9.63472603E+01,
     7.17788999E+01,  4.09339278E+02, -8.69123335E+01,  2.33731491E+03, -3.79574592E+02,  1.33952983E+03, -7.17788999E+01, -4.09339278E+02,  8.69123335E+01,  2.01681487E+03,  9.63472603E+01,  9.22503258E+02,
    -2.89683331E+02,  1.45098439E+02,  3.11628803E+02,  2.58048990E+02,  6.69344650E+02, -7.17788999E+01,  2.89683331E+02, -1.45098439E+02, -3.11628803E+02,  2.58048990E+02,  6.69344650E+02, -7.17788999E+01,
     1.45098439E+02, -2.50794775E+02, -1.52212348E+02, -1.02565535E+03, -3.44961324E+02, -4.09339278E+02, -1.45098439E+02,  2.50794775E+02,  1.52212348E+02, -1.02565535E+03, -3.44961324E+02, -4.09339278E+02,
     3.11628803E+02, -1.52212348E+02, -7.98521894E+02,  4.36721100E+02,  4.38160722E+02,  8.69123335E+01, -3.11628803E+02,  1.52212348E+02,  7.98521894E+02,  4.36721100E+02,  4.38160722E+02,  8.69123335E+01,
    -2.58048990E+02,  1.02565535E+03, -4.36721100E+02,  5.50332742E+03,  2.54449612E+03,  2.01681487E+03,  2.58048990E+02, -1.02565535E+03,  4.36721100E+02,  6.06338939E+03,  2.21959929E+03,  2.33731491E+03,
    -6.69344650E+02,  3.44961324E+02, -4.38160722E+02,  2.54449612E+03,  3.86266933E+03,  9.63472603E+01,  6.69344650E+02, -3.44961324E+02,  4.38160722E+02,  2.21959929E+03,  5.02158078E+03, -3.79574592E+02,
     7.17788999E+01,  4.09339278E+02, -8.69123335E+01,  2.01681487E+03,  9.63472603E+01,  9.22503258E+02, -7.17788999E+01, -4.09339278E+02,  8.69123335E+01,  2.33731491E+03, -3.79574592E+02,  1.33952983E+03
    });

    // Check
    ASSERT_TRUE (kgTarget == kgTest);
}

// 非重合节点：朝向节点 + OCID>0(Si 偏置，直角坐标系)
TEST_F (BushCalculatorTest, ComputeStiffnessWithTwoGridsGOROCIDgt0)
{
    // Input data
    element.m_go   = 9;
    element.m_oCId = 101;
    element.m_s1   = 1.0;
    element.m_s2   = 2.0;
    element.m_s3   = 3.0;

    const Real* K{property.m_K};

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kgTest (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kgTest);
    kgTest = TEleOffset.Transpose () * kgTest * TEleOffset;

    // Target data
    const Matrixd kgTarget (n, n, {
     2.89683331E+02, -1.45098439E+02, -3.11628803E+02,  1.66357149E+03, -5.73782912E+03,  4.21802788E+03, -2.89683331E+02,  1.45098439E+02,  3.11628803E+02, -2.17966947E+03,  4.39913982E+03, -4.07447008E+03,
    -1.45098439E+02,  2.50794775E+02,  1.52212348E+02,  1.16699406E+03,  2.84225701E+03, -3.57063139E+03,  1.45098439E+02, -2.50794775E+02, -1.52212348E+02,  8.84316638E+02, -2.15233436E+03,  4.38930995E+03,
    -3.11628803E+02,  1.52212348E+02,  7.98521894E+02, -6.67873628E+03,  9.96447483E+03, -4.50582849E+03,  3.11628803E+02, -1.52212348E+02, -7.98521894E+02,  5.80529408E+03, -1.08407963E+04,  4.33200383E+03,
     1.66357149E+03,  1.16699406E+03, -6.67873628E+03,  8.29864446E+04, -7.31305789E+04,  8.01123473E+03, -1.66357149E+03, -1.16699406E+03,  6.67873628E+03, -5.12802951E+04,  8.98885454E+04,  2.81445005E+03,
    -5.73782912E+03,  2.84225701E+03,  9.96447483E+03, -7.31305789E+04,  1.45267114E+05, -8.35256593E+04,  5.73782912E+03, -2.84225701E+03, -9.96447483E+03,  7.16597244E+04, -1.37711197E+05,  8.05234569E+04,
     4.21802788E+03, -3.57063139E+03, -4.50582849E+03,  8.01123473E+03, -8.35256593E+04,  7.35591397E+04, -4.21802788E+03,  3.57063139E+03,  4.50582849E+03, -3.02000631E+04,  6.38745229E+04, -7.87582130E+04,
    -2.89683331E+02,  1.45098439E+02,  3.11628803E+02, -1.66357149E+03,  5.73782912E+03, -4.21802788E+03,  2.89683331E+02, -1.45098439E+02, -3.11628803E+02,  2.17966947E+03, -4.39913982E+03,  4.07447008E+03,
     1.45098439E+02, -2.50794775E+02, -1.52212348E+02, -1.16699406E+03, -2.84225701E+03,  3.57063139E+03, -1.45098439E+02,  2.50794775E+02,  1.52212348E+02, -8.84316638E+02,  2.15233436E+03, -4.38930995E+03,
     3.11628803E+02, -1.52212348E+02, -7.98521894E+02,  6.67873628E+03, -9.96447483E+03,  4.50582849E+03, -3.11628803E+02,  1.52212348E+02,  7.98521894E+02, -5.80529408E+03,  1.08407963E+04, -4.33200383E+03,
    -2.17966947E+03,  8.84316638E+02,  5.80529408E+03, -5.12802951E+04,  7.16597244E+04, -3.02000631E+04,  2.17966947E+03, -8.84316638E+02, -5.80529408E+03,  4.27075793E+04, -7.88895002E+04,  2.80826379E+04,
     4.39913982E+03, -2.15233436E+03, -1.08407963E+04,  8.98885454E+04, -1.37711197E+05,  6.38745229E+04, -4.39913982E+03,  2.15233436E+03,  1.08407963E+04, -7.88895002E+04,  1.47923780E+05, -6.14387752E+04,
    -4.07447008E+03,  4.38930995E+03,  4.33200383E+03,  2.81445005E+03,  8.05234569E+04, -7.87582130E+04,  4.07447008E+03, -4.38930995E+03, -4.33200383E+03,  2.80826379E+04, -6.14387752E+04,  8.84813525E+04
    });

    // Check
    ASSERT_TRUE (kgTarget == kgTest);
}

// 非重合节点：CID、朝向节点、朝向矢量均未指定，1、4 方向 Ki 至少一个不为 0.0，同时 2、3、5、6 方向的 Ki 必须为 0.0 + OCID=0(Si 偏置)
TEST_F (BushCalculatorTest, ComputeStiffnessWithTwoGridsK1OCIDeq0)
{
    // Input data
    element.m_oCId = 0;
    element.m_s1   = 1.0;
    element.m_s2   = 2.0;
    element.m_s3   = 3.0;

    property.m_K[1] = 0.0;
    property.m_K[2] = 0.0;
    property.m_K[3] = 0.0;
    property.m_K[4] = 0.0;
    property.m_K[5] = 0.0;
    const Real* K{property.m_K};

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kgTest (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kgTest);
    kgTest = TEle.Transpose () * kgTest * TEle;

    // Target data
    const Matrixd kgTarget (n, n, {
     1.86567164E+02, -1.11940299E+02, -3.73134328E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -1.86567164E+02,  1.11940299E+02,  3.73134328E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
    -1.11940299E+02,  6.71641791E+01,  2.23880597E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  1.11940299E+02, -6.71641791E+01, -2.23880597E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
    -3.73134328E+02,  2.23880597E+02,  7.46268657E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  3.73134328E+02, -2.23880597E+02, -7.46268657E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
    -1.86567164E+02,  1.11940299E+02,  3.73134328E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  1.86567164E+02, -1.11940299E+02, -3.73134328E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     1.11940299E+02, -6.71641791E+01, -2.23880597E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -1.11940299E+02,  6.71641791E+01,  2.23880597E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     3.73134328E+02, -2.23880597E+02, -7.46268657E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -3.73134328E+02,  2.23880597E+02,  7.46268657E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00
    });

    // Check
    ASSERT_TRUE (kgTarget == kgTest);
}

// 非重合节点：节点定义直角坐标系 + 位移输出直角坐标系 + 朝向矢量 + OCID=-1(S 偏置)
TEST_F (BushCalculatorTest, ComputeStiffnessWithTwoGridsRCPRCDOrienVectorOCIDlt0)
{
    // Input data
    nodeSet[0].m_defCoord  = 100;
    nodeSet[0].m_dispCoord = 101;
    nodeSet[1].m_defCoord  = 101;
    nodeSet[1].m_dispCoord = 100;
    orienNode.m_defCoord   = 101;

    element.m_x1 = -10.0;
    element.m_x2 = -12.0;
    element.m_x3 = -13.0;

    const Real* K{property.m_K};

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kgTest (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kgTest);
    kgTest = TEleOffset.Transpose () * kgTest * TEleOffset;

    // Target data
    const Matrixd kgTarget (n, n, {
     2.11920759E+02, -8.94453107E+01,  1.08669144E+01, -5.62733664E+02, -1.48963698E+03, -1.28703485E+03, -2.12544595E+02, -6.45249252E+01, -6.07477616E+01,  5.95333217E+02, -1.95900995E+03, -2.13813357E+00,
    -8.94453107E+01,  5.17106388E+02, -4.28081527E+02,  9.07632989E+02,  2.78757455E+02,  1.47083539E+02,  1.52781576E+02, -4.05629143E+01,  6.58533001E+02,  5.93706465E+02,  7.49844902E+02, -9.15542803E+01,
     1.08669144E+01, -4.28081527E+02,  6.09972853E+02,  8.90017826E+02,  4.27230597E+02,  2.83976209E+02,  1.21772939E+01, -7.38385364E+01, -7.41510856E+02,  4.69596421E+02,  9.09894484E+02, -8.28940843E+01,
    -5.62733664E+02,  9.07632989E+02,  8.90017826E+02,  1.27841339E+04,  4.57152589E+03,  2.66427380E+03,  1.15861149E+03, -7.61034334E+02, -1.05093815E+02,  6.54022520E+03,  1.09944327E+04, -1.10393870E+03,
    -1.48963698E+03,  2.78757455E+02,  4.27230597E+02,  4.57152589E+03,  1.10896255E+04,  9.48491724E+03,  1.51309206E+03,  3.95274385E+02, -1.83195574E+02, -3.56506682E+03,  1.44727277E+04, -3.94352334E+01,
    -1.28703485E+03,  1.47083539E+02,  2.83976209E+02,  2.66427380E+03,  9.48491724E+03,  8.35926726E+03,  1.23870050E+03,  4.47898944E+02, -1.54085562E+02, -4.01050038E+03,  1.18558804E+04,  1.64356038E+01,
    -2.12544595E+02,  1.52781576E+02,  1.21772939E+01,  1.15861149E+03,  1.51309206E+03,  1.23870050E+03,  2.47861590E+02,  1.21105021E+01,  8.41645363E+01, -8.88172103E+01,  2.27025985E+03, -6.51059458E+01,
    -6.45249252E+01, -4.05629143E+01, -7.38385364E+01, -7.61034334E+02,  3.95274385E+02,  4.47898944E+02,  1.21105021E+01,  1.01539193E+02,  2.83561905E+01, -9.58021189E+02,  8.49669590E+01,  1.04902709E+02,
    -6.07477616E+01,  6.58533001E+02, -7.41510856E+02, -1.05093815E+02, -1.83195574E+02, -1.54085562E+02,  8.41645363E+01,  2.83561905E+01,  9.89599217E+02,  4.16738269E+01, -2.58062311E+02,  3.85025136E+00,
     5.95333217E+02,  5.93706465E+02,  4.69596421E+02,  6.54022520E+03, -3.56506682E+03, -4.01050038E+03, -8.88172103E+01, -9.58021189E+02,  4.16738269E+01,  9.91362769E+03, -8.55094727E+02, -1.07992588E+03,
    -1.95900995E+03,  7.49844902E+02,  9.09894484E+02,  1.09944327E+04,  1.44727277E+04,  1.18558804E+04,  2.27025985E+03,  8.49669590E+01, -2.58062311E+02, -8.55094727E+02,  2.21200218E+04, -6.33623574E+02,
    -2.13813357E+00, -9.15542803E+01, -8.28940843E+01, -1.10393870E+03, -3.94352334E+01,  1.64356038E+01, -6.51059458E+01,  1.04902709E+02,  3.85025136E+00, -1.07992588E+03, -6.33623574E+02,  1.99377165E+02
    });

    // Check
    ASSERT_TRUE (kgTarget == kgTest);
}

// 非重合节点：节点定义柱坐标系 + 位移输出柱坐标系 + 朝向矢量 + OCID=-1(S 偏置)
TEST_F (BushCalculatorTest, ComputeStiffnessWithTwoGridsCCPCCDOrienVectorOCIDlt0)
{
    // Input data
    nodeSet[0].m_defCoord  = 200;
    nodeSet[0].m_dispCoord = 201;
    nodeSet[1].m_defCoord  = 201;
    nodeSet[1].m_dispCoord = 200;
    orienNode.m_defCoord   = 201;

    element.m_x1 = -10.0;
    element.m_x2 = -12.0;
    element.m_x3 = -13.0;

    const Real* K{property.m_K};

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kgTest (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kgTest);
    kgTest = TEleOffset.Transpose () * kgTest * TEleOffset;

    // Target data
    const Matrixd kgTarget (n, n, {
     2.89212027E+02, -2.34691710E+02,  9.46102394E+01, -4.11886369E+02, -9.59320580E+02, -1.12061968E+03, -5.82031457E+01,  2.21409873E+02, -3.08650215E+02, -1.00020577E+03, -1.02353447E+03, -5.45619299E+02,
    -2.34691710E+02,  6.39412002E+02, -3.72933416E+02,  4.42327450E+02,  3.82494920E+01, -2.12781687E+02, -2.43402211E+02, -2.31846835E+02,  7.00006892E+02,  3.41987679E+02, -3.54167296E+02,  1.61139958E+00,
     9.46102394E+01, -3.72933416E+02,  4.10375970E+02,  8.80492417E+02,  6.34523977E+02,  3.73636877E+02,  1.64676276E+02, -1.21004128E+01, -5.37749171E+02,  1.09288185E+03,  1.13094079E+02,  3.32131109E+02,
    -4.11886369E+02,  4.42327450E+02,  8.80492417E+02,  7.60836374E+03,  3.91910715E+03,  1.03040094E+03, -3.43024871E+01, -1.03003523E+03, -2.80038609E+02,  7.43962131E+03, -3.01858415E+02,  1.95944307E+03,
    -9.59320580E+02,  3.82494920E+01,  6.34523977E+02,  3.91910715E+03,  5.67745137E+03,  5.65510838E+03,  6.52246211E+02, -9.45697523E+02, -6.79025162E+01,  6.76742451E+03,  4.39827198E+03,  3.07515467E+03,
    -1.12061968E+03, -2.12781687E+02,  3.73636877E+02,  1.03040094E+03,  5.65510838E+03,  7.50783001E+03,  9.51938322E+02, -7.27495096E+02,  7.23418082E+01,  5.19163906E+03,  6.48762970E+03,  3.10760415E+03,
    -5.82031457E+01, -2.43402211E+02,  1.64676276E+02, -3.43024871E+01,  6.52246211E+02,  9.51938322E+02,  2.00200591E+02, -5.61270401E+00, -2.22797530E+02,  4.57068668E+02,  9.87424531E+02,  3.85835945E+02,
     2.21409873E+02, -2.31846835E+02, -1.21004128E+01, -1.03003523E+03, -9.45697523E+02, -7.27495096E+02, -5.61270401E+00,  2.52434388E+02, -1.97906756E+02, -1.42862387E+03, -4.30314321E+02, -5.08359044E+02,
    -3.08650215E+02,  7.00006892E+02, -5.37749171E+02, -2.80038609E+02, -6.79025162E+01,  7.23418082E+01, -2.22797530E+02, -1.97906756E+02,  8.86365022E+02, -2.48756879E+02,  1.60218387E+02, -2.67543467E+01,
    -1.00020577E+03,  3.41987679E+02,  1.09288185E+03,  7.43962131E+03,  6.76742451E+03,  5.19163906E+03,  4.57068668E+02, -1.42862387E+03, -2.48756879E+02,  1.10217421E+04,  2.50062812E+03,  3.69101040E+03,
    -1.02353447E+03, -3.54167296E+02,  1.13094079E+02, -3.01858415E+02,  4.39827198E+03,  6.48762970E+03,  9.87424531E+02, -4.30314321E+02,  1.60218387E+02,  2.50062812E+03,  7.96611814E+03,  2.76937049E+03,
    -5.45619299E+02,  1.61139958E+00,  3.32131109E+02,  1.95944307E+03,  3.07515467E+03,  3.10760415E+03,  3.85835945E+02, -5.08359044E+02, -2.67543467E+01,  3.69101040E+03,  2.76937049E+03,  1.80578487E+03
    });

    // Check
    ASSERT_TRUE (kgTarget == kgTest);
}

// 非重合节点：节点定义球坐标系 + 位移输出球坐标系 + 朝向矢量 + OCID=-1(S 偏置)
TEST_F (BushCalculatorTest, ComputeStiffnessWithTwoGridsSCPSCDOrienVectorOCIDlt0)
{
    // Input data
    nodeSet[0].m_defCoord  = 300;
    nodeSet[0].m_dispCoord = 301;
    nodeSet[1].m_defCoord  = 301;
    nodeSet[1].m_dispCoord = 300;
    orienNode.m_defCoord   = 301;

    element.m_x1 = -10.0;
    element.m_x2 = -12.0;
    element.m_x3 = -13.0;

    const Real* K{property.m_K};

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kgTest (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kgTest);
    kgTest = TEleOffset.Transpose () * kgTest * TEleOffset;

    // Target data
    const Matrixd kgTarget (n, n, {
     2.81530532E+02, -2.54712852E+02,  3.96558853E+01,  1.67012517E+02,  2.57163300E+02,  4.66101678E+02, -3.22995885E+02, -1.69598632E+02, -1.12341572E+02,  6.70472857E+01,  2.11418473E+02, -5.11941216E+02,
    -2.54712852E+02,  7.84057250E+02, -2.87627446E+02, -9.78204818E+01,  6.29326863E+00,  1.03781531E+02,  3.82836461E+02,  6.85420033E+02,  3.82085826E+02, -1.06142286E+02,  8.42778308E+01, -4.48343675E+01,
     3.96558853E+01, -2.87627446E+02,  2.73412218E+02, -3.86273393E+02, -2.17997043E+02, -1.73305786E+02, -7.26054473E+01, -3.88609025E+02, -5.26103862E+01, -3.15640951E+02,  1.07227072E+01,  3.56399430E+02,
     1.67012517E+02, -9.78204818E+01, -3.86273393E+02,  1.62071196E+03,  6.03026912E+02,  3.05256240E+01, -2.18329385E+02,  2.59373597E+02, -2.67818554E+02,  3.57161662E+02,  1.86490656E+02, -8.56952196E+02,
     2.57163300E+02,  6.29326863E+00, -2.17997043E+02,  6.03026912E+02,  5.73411282E+02,  6.93369601E+02, -2.69308034E+02,  1.91272254E+02, -6.77007112E+01,  3.33623716E+02,  2.39638527E+02, -7.61348649E+02,
     4.66101678E+02,  1.03781531E+02, -1.73305786E+02,  3.05256240E+01,  6.93369601E+02,  1.69422542E+03, -4.48746518E+02,  2.24164706E+02,  8.02061263E+01,  4.04108659E+02,  2.81641035E+02, -1.11242986E+03,
    -3.22995885E+02,  3.82836461E+02, -7.26054473E+01, -2.18329385E+02, -2.69308034E+02, -4.48746518E+02,  3.86693661E+02,  2.70358218E+02,  1.83128630E+02, -1.16147145E+02, -1.87691409E+02,  5.22350218E+02,
    -1.69598632E+02,  6.85420033E+02, -3.88609025E+02,  2.59373597E+02,  1.91272254E+02,  2.24164706E+02,  2.70358218E+02,  7.11710648E+02,  2.64491359E+02,  1.92813969E+02,  5.23377257E+01, -3.37924680E+02,
    -1.12341572E+02,  3.82085826E+02, -5.26103862E+01, -2.67818554E+02, -6.77007112E+01,  8.02061263E+01,  1.83128630E+02,  2.64491359E+02,  2.40595691E+02, -2.54407837E+02,  1.18102487E+02,  6.38094192E+01,
     6.70472857E+01, -1.06142286E+02, -3.15640951E+02,  3.57161662E+02,  3.33623716E+02,  4.04108659E+02, -1.16147145E+02,  1.92813969E+02, -2.54407837E+02,  1.35639763E+03, -5.30311043E+02, -4.74729806E+02,
     2.11418473E+02,  8.42778308E+01,  1.07227072E+01,  1.86490656E+02,  2.39638527E+02,  2.81641035E+02, -1.87691409E+02,  5.23377257E+01,  1.18102487E+02, -5.30311043E+02,  6.65917825E+02, -6.07469950E+02,
    -5.11941216E+02, -4.48343675E+01,  3.56399430E+02, -8.56952196E+02, -7.61348649E+02, -1.11242986E+03,  5.22350218E+02, -3.37924680E+02,  6.38094192E+01, -4.74729806E+02, -6.07469950E+02,  1.86603321E+03
    });

    // Check
    ASSERT_TRUE (kgTarget == kgTest);
}

// 非重合节点：节点定义球坐标系 + 位移输出球坐标系 + 朝向节点 + OCID=-1(S 偏置)
TEST_F (BushCalculatorTest, ComputeStiffnessWithTwoGridsSCPSCDGOOCIDlt0)
{
    // Input data
    nodeSet[0].m_defCoord  = 300;
    nodeSet[0].m_dispCoord = 301;
    nodeSet[1].m_defCoord  = 301;
    nodeSet[1].m_dispCoord = 300;
    orienNode.m_defCoord   = 301;

    element.m_go = 9;

    const Real* K{property.m_K};

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kgTest (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kgTest);
    kgTest = TEleOffset.Transpose () * kgTest * TEleOffset;

    // Target data
    const Matrixd kgTarget (n, n, {
     1.97466250E+02, -2.58183137E+02,  1.07524058E+02, -2.84217094E-14,  1.04714980E+02,  2.51438074E+02, -2.35563807E+02, -2.30249677E+02, -9.33148101E+01, -4.46259880E+01,  1.38876717E+02, -2.30017631E+02,
    -2.58183137E+02,  8.04459105E+02, -2.35493527E+02, -2.50268802E+02, -4.68261208E+01,  1.14421341E+02,  3.95201407E+02,  6.55668620E+02,  4.28000810E+02, -2.44742302E+02,  1.32164414E+02,  2.35196825E+01,
     1.07524058E+02, -2.35493527E+02,  3.37074645E+02, -6.00936996E+02, -2.07357233E+02,  4.68261208E+01, -1.22168833E+02, -4.05069368E+02,  4.03921235E+01, -5.47215281E+02,  1.91462548E+02,  2.64976434E+02,
    -2.84217094E-14, -2.50268802E+02, -6.00936996E+02,  1.97718452E+03,  6.17742572E+02, -2.57267724E+02, -1.06656111E+02,  3.31915354E+02, -5.49742139E+02,  1.44121007E+03, -5.65506448E+02, -6.21044142E+02,
     1.04714980E+02, -4.68261208E+01, -2.07357233E+02,  6.17742572E+02,  4.86897709E+02,  4.72296975E+02, -1.30708018E+02,  1.43385672E+02, -1.36054761E+02,  4.86933572E+02, -1.29241771E+02, -1.92060285E+02,
     2.51438074E+02,  1.14421341E+02,  4.68261208E+01, -2.57267724E+02,  4.72296975E+02,  1.42426643E+03, -2.17172188E+02,  4.34248650E+01,  1.71629122E+02, -2.10415340E+02,  7.75533616E+01,  4.06849372E+01,
    -2.35563807E+02,  3.95201407E+02, -1.22168833E+02, -1.06656111E+02, -1.30708018E+02, -2.17172188E+02,  2.99490222E+02,  3.21827044E+02,  1.82572297E+02, -5.71020108E+01, -9.05596241E+01,  2.53302559E+02,
    -2.30249677E+02,  6.55668620E+02, -4.05069368E+02,  3.31915354E+02,  1.43385672E+02,  4.34248650E+01,  3.21827044E+02,  7.04088688E+02,  2.18366479E+02,  2.89945754E+02, -6.74804539E+01, -2.09739886E+02,
    -9.33148101E+01,  4.28000810E+02,  4.03921235E+01, -5.49742139E+02, -1.36054761E+02,  1.71629122E+02,  1.82572297E+02,  2.18366479E+02,  3.35421090E+02, -5.23455497E+02,  2.46287281E+02,  1.24582465E+02,
    -4.46259880E+01, -2.44742302E+02, -5.47215281E+02,  1.44121007E+03,  4.86933572E+02, -2.10415340E+02, -5.71020108E+01,  2.89945754E+02, -5.23455497E+02,  1.72618171E+03, -7.48563356E+02, -4.72370693E+02,
     1.38876717E+02,  1.32164414E+02,  1.91462548E+02, -5.65506448E+02, -1.29241771E+02,  7.75533616E+01, -9.05596241E+01, -6.74804539E+01,  2.46287281E+02, -7.48563356E+02,  6.98238558E+02, -4.11878512E+02,
    -2.30017631E+02,  2.35196825E+01,  2.64976434E+02, -6.21044142E+02, -1.92060285E+02,  4.06849372E+01,  2.53302559E+02, -2.09739886E+02,  1.24582465E+02, -4.72370693E+02, -4.11878512E+02,  1.46392840E+03
    });

    // Check
    ASSERT_TRUE (kgTarget == kgTest);
}

// 非重合节点：CID>0(柱坐标系) + OCID=-1(S 偏置)
TEST_F (BushCalculatorTest, ComputeStiffnessWithTwoGridsCCIDgt0OCIDlt0)
{
    // Input data
    element.m_coordId = 201;

    const Real* K{property.m_K};

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kgTest (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kgTest);
    kgTest = TEleOffset.Transpose () * kgTest * TEleOffset;

    // Target data
    const Matrixd kgTarget (n, n, {
     2.24349461E+02,  2.63071314E+02,  1.36419170E+02,  1.11072781E+03, -1.46279523E+03,  9.94202476E+02, -2.24349461E+02, -2.63071314E+02, -1.36419170E+02,  1.11072781E+03, -1.46279523E+03,  9.94202476E+02,
     2.63071314E+02,  8.19775052E+02,  2.02697088E+02,  3.79482963E+03, -1.82209929E+03,  2.44404460E+03, -2.63071314E+02, -8.19775052E+02, -2.02697088E+02,  3.79482963E+03, -1.82209929E+03,  2.44404460E+03,
     1.36419170E+02,  2.02697088E+02,  2.94875487E+02,  5.71172208E+02, -1.41928457E+03,  7.11371474E+02, -1.36419170E+02, -2.02697088E+02, -2.94875487E+02,  5.71172208E+02, -1.41928457E+03,  7.11371474E+02,
     1.11072781E+03,  3.79482963E+03,  5.71172208E+02,  1.83649584E+04, -7.10234831E+03,  1.12732536E+04, -1.11072781E+03, -3.79482963E+03, -5.71172208E+02,  1.78698212E+04, -6.86079087E+03,  1.10330780E+04,
    -1.46279523E+03, -1.82209929E+03, -1.41928457E+03, -7.10234831E+03,  1.10610523E+04, -7.00424914E+03,  1.46279523E+03,  1.82209929E+03,  1.41928457E+03, -6.86079087E+03,  1.06633229E+04, -6.49463300E+03,
     9.94202476E+02,  2.44404460E+03,  7.11371474E+02,  1.12732536E+04, -7.00424914E+03,  8.22298192E+03, -9.94202476E+02, -2.44404460E+03, -7.11371474E+02,  1.10330780E+04, -6.49463300E+03,  6.97984851E+03,
    -2.24349461E+02, -2.63071314E+02, -1.36419170E+02, -1.11072781E+03,  1.46279523E+03, -9.94202476E+02,  2.24349461E+02,  2.63071314E+02,  1.36419170E+02, -1.11072781E+03,  1.46279523E+03, -9.94202476E+02,
    -2.63071314E+02, -8.19775052E+02, -2.02697088E+02, -3.79482963E+03,  1.82209929E+03, -2.44404460E+03,  2.63071314E+02,  8.19775052E+02,  2.02697088E+02, -3.79482963E+03,  1.82209929E+03, -2.44404460E+03,
    -1.36419170E+02, -2.02697088E+02, -2.94875487E+02, -5.71172208E+02,  1.41928457E+03, -7.11371474E+02,  1.36419170E+02,  2.02697088E+02,  2.94875487E+02, -5.71172208E+02,  1.41928457E+03, -7.11371474E+02,
     1.11072781E+03,  3.79482963E+03,  5.71172208E+02,  1.78698212E+04, -6.86079087E+03,  1.10330780E+04, -1.11072781E+03, -3.79482963E+03, -5.71172208E+02,  1.83649584E+04, -7.10234831E+03,  1.12732536E+04,
    -1.46279523E+03, -1.82209929E+03, -1.41928457E+03, -6.86079087E+03,  1.06633229E+04, -6.49463300E+03,  1.46279523E+03,  1.82209929E+03,  1.41928457E+03, -7.10234831E+03,  1.10610523E+04, -7.00424914E+03,
     9.94202476E+02,  2.44404460E+03,  7.11371474E+02,  1.10330780E+04, -6.49463300E+03,  6.97984851E+03, -9.94202476E+02, -2.44404460E+03, -7.11371474E+02,  1.12732536E+04, -7.00424914E+03,  8.22298192E+03
    });

    // Check
    ASSERT_TRUE (kgTarget == kgTest);
}

// // 测试 GA 落在柱、球坐标系 Z 轴上
// TEST_F (BushCalculatorTest, Test)
// {
//     // Input data
//     nodeSet[0] = {7, 0, {10.0, 1.0, 1.0}, 0};
//     element.m_coordId = 202;

//     const Real* K{property.m_K};

//     // Test data
//     const std::size_t n{6 * nEleNodes};
//     Matrixd TEle (n, n);
//     BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT TEle);
//     Matrixd kgTest (n, n);
//     BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kgTest);
//     kgTest = TEle.Transpose () * kgTest * TEle;

//     // Target data
//     const Matrixd kgTarget (n, n, {
//      2.24349461E+02,  2.63071314E+02,  1.36419170E+02,  1.11072781E+03, -1.46279523E+03,  9.94202476E+02, -2.24349461E+02, -2.63071314E+02, -1.36419170E+02,  1.11072781E+03, -1.46279523E+03,  9.94202476E+02,
//      2.63071314E+02,  8.19775052E+02,  2.02697088E+02,  3.79482963E+03, -1.82209929E+03,  2.44404460E+03, -2.63071314E+02, -8.19775052E+02, -2.02697088E+02,  3.79482963E+03, -1.82209929E+03,  2.44404460E+03,
//      1.36419170E+02,  2.02697088E+02,  2.94875487E+02,  5.71172208E+02, -1.41928457E+03,  7.11371474E+02, -1.36419170E+02, -2.02697088E+02, -2.94875487E+02,  5.71172208E+02, -1.41928457E+03,  7.11371474E+02,
//      1.11072781E+03,  3.79482963E+03,  5.71172208E+02,  1.83649584E+04, -7.10234831E+03,  1.12732536E+04, -1.11072781E+03, -3.79482963E+03, -5.71172208E+02,  1.78698212E+04, -6.86079087E+03,  1.10330780E+04,
//     -1.46279523E+03, -1.82209929E+03, -1.41928457E+03, -7.10234831E+03,  1.10610523E+04, -7.00424914E+03,  1.46279523E+03,  1.82209929E+03,  1.41928457E+03, -6.86079087E+03,  1.06633229E+04, -6.49463300E+03,
//      9.94202476E+02,  2.44404460E+03,  7.11371474E+02,  1.12732536E+04, -7.00424914E+03,  8.22298192E+03, -9.94202476E+02, -2.44404460E+03, -7.11371474E+02,  1.10330780E+04, -6.49463300E+03,  6.97984851E+03,
//     -2.24349461E+02, -2.63071314E+02, -1.36419170E+02, -1.11072781E+03,  1.46279523E+03, -9.94202476E+02,  2.24349461E+02,  2.63071314E+02,  1.36419170E+02, -1.11072781E+03,  1.46279523E+03, -9.94202476E+02,
//     -2.63071314E+02, -8.19775052E+02, -2.02697088E+02, -3.79482963E+03,  1.82209929E+03, -2.44404460E+03,  2.63071314E+02,  8.19775052E+02,  2.02697088E+02, -3.79482963E+03,  1.82209929E+03, -2.44404460E+03,
//     -1.36419170E+02, -2.02697088E+02, -2.94875487E+02, -5.71172208E+02,  1.41928457E+03, -7.11371474E+02,  1.36419170E+02,  2.02697088E+02,  2.94875487E+02, -5.71172208E+02,  1.41928457E+03, -7.11371474E+02,
//      1.11072781E+03,  3.79482963E+03,  5.71172208E+02,  1.78698212E+04, -6.86079087E+03,  1.10330780E+04, -1.11072781E+03, -3.79482963E+03, -5.71172208E+02,  1.83649584E+04, -7.10234831E+03,  1.12732536E+04,
//     -1.46279523E+03, -1.82209929E+03, -1.41928457E+03, -6.86079087E+03,  1.06633229E+04, -6.49463300E+03,  1.46279523E+03,  1.82209929E+03,  1.41928457E+03, -7.10234831E+03,  1.10610523E+04, -7.00424914E+03,
//      9.94202476E+02,  2.44404460E+03,  7.11371474E+02,  1.10330780E+04, -6.49463300E+03,  6.97984851E+03, -9.94202476E+02, -2.44404460E+03, -7.11371474E+02,  1.12732536E+04, -7.00424914E+03,  8.22298192E+03
//     });

//     // Check
//     ASSERT_TRUE (kgTarget == kgTest);
// }

// 非重合节点：CID>0(球坐标系) + OCID>0(Si 偏置，球坐标系)
TEST_F (BushCalculatorTest, ComputeStiffnessWithTwoGridsSCIDgt0SOCIDgt0)
{
    // Input data
    element.m_coordId = 301;
    element.m_oCId    = 300;
    element.m_s1      = 1.0;
    element.m_s2      = 2.0;
    element.m_s3      = 3.0;

    const Real* K{property.m_K};

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kgTest (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kgTest);
    kgTest = TEleOffset.Transpose () * kgTest * TEleOffset;

    // Target data
    const Matrixd kgTarget (n, n, {
     3.72200449E+02,  2.43761798E+02,  1.66147416E+02,  1.36889978E+03, -3.28153607E+03,  1.74789368E+03, -3.72200449E+02, -2.43761798E+02, -1.66147416E+02,  5.70275948E+02, -1.27120550E+03,  5.87516653E+02,
     2.43761798E+02,  5.56247191E+02,  3.71869663E+02,  3.19897753E+03,  1.23549592E+02, -2.28174738E+03, -2.43761798E+02, -5.56247191E+02, -3.71869663E+02,  1.24788539E+03, -4.42051588E+03,  5.79426872E+03,
     1.66147416E+02,  3.71869663E+02,  4.10552360E+02,  4.61785565E+02,  1.44137634E+03, -1.49244937E+03, -1.66147416E+02, -3.71869663E+02, -4.10552360E+02,  2.02525399E+03, -5.15561229E+03,  3.85023994E+03,
     1.36889978E+03,  3.19897753E+03,  4.61785565E+02,  3.64016951E+04, -1.35152705E+04, -1.37067117E+04, -1.36889978E+03, -3.19897753E+03, -4.61785565E+02, -5.79727646E+03, -2.48265514E+03,  3.38082987E+04,
    -3.28153607E+03,  1.23549592E+02,  1.44137634E+03, -1.35152705E+04,  5.42055131E+04, -3.50631669E+04,  3.28153607E+03, -1.23549592E+02, -1.44137634E+03,  1.04266374E+04, -2.85970341E+04,  2.58363066E+04,
     1.74789368E+03, -2.28174738E+03, -1.49244937E+03, -1.37067117E+04, -3.50631669E+04,  3.80728332E+04, -1.74789368E+03,  2.28174738E+03,  1.49244937E+03, -4.63341394E+03,  2.50464769E+04, -4.42378890E+04,
    -3.72200449E+02, -2.43761798E+02, -1.66147416E+02, -1.36889978E+03,  3.28153607E+03, -1.74789368E+03,  3.72200449E+02,  2.43761798E+02,  1.66147416E+02, -5.70275948E+02,  1.27120550E+03, -5.87516653E+02,
    -2.43761798E+02, -5.56247191E+02, -3.71869663E+02, -3.19897753E+03, -1.23549592E+02,  2.28174738E+03,  2.43761798E+02,  5.56247191E+02,  3.71869663E+02, -1.24788539E+03,  4.42051588E+03, -5.79426872E+03,
    -1.66147416E+02, -3.71869663E+02, -4.10552360E+02, -4.61785565E+02, -1.44137634E+03,  1.49244937E+03,  1.66147416E+02,  3.71869663E+02,  4.10552360E+02, -2.02525399E+03,  5.15561229E+03, -3.85023994E+03,
     5.70275948E+02,  1.24788539E+03,  2.02525399E+03, -5.79727646E+03,  1.04266374E+04, -4.63341394E+03, -5.70275948E+02, -1.24788539E+03, -2.02525399E+03,  1.22003684E+04, -2.62556668E+04,  1.25836687E+04,
    -1.27120550E+03, -4.42051588E+03, -5.15561229E+03, -2.48265514E+03, -2.85970341E+04,  2.50464769E+04,  1.27120550E+03,  4.42051588E+03,  5.15561229E+03, -2.62556668E+04,  6.70871505E+04, -5.09626728E+04,
     5.87516653E+02,  5.79426872E+03,  3.85023994E+03,  3.38082987E+04,  2.58363066E+04, -4.42378890E+04, -5.87516653E+02, -5.79426872E+03, -3.85023994E+03,  1.25836687E+04, -5.09626728E+04,  7.49717826E+04
    });

    // Check
    ASSERT_TRUE (kgTarget == kgTest);
}

// 非重合节点：CID=0 + OCID>0(Si 偏置，柱坐标系)
TEST_F (BushCalculatorTest, ComputeStiffnessWithTwoGridsCIDeq0COCIDgt0)
{
    // Input data
    element.m_coordId = 0;
    element.m_oCId    = 201;
    element.m_s1      = 1.0;
    element.m_s2      = 2.0;
    element.m_s3      = 3.0;

    const Real* K{property.m_K};

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kgTest (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kgTest);
    kgTest = TEleOffset.Transpose () * kgTest * TEleOffset;

    // Target data
    const Matrixd kgTarget (n, n, {
     1.00000000E+03,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -1.10830937E+04,  9.48650167E+03, -1.00000000E+03,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  1.08309368E+03, -6.48650167E+03,
     0.00000000E+00,  1.00000000E+02,  0.00000000E+00,  1.10830937E+03,  0.00000000E+00, -6.48047147E+02,  0.00000000E+00, -1.00000000E+02,  0.00000000E+00, -1.08309368E+02,  0.00000000E+00,  1.14804715E+03,
     0.00000000E+00,  0.00000000E+00,  2.39000000E+02, -2.26727390E+03,  1.54883268E+03,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -2.39000000E+02,  1.55027390E+03, -2.74383268E+03,  0.00000000E+00,
     0.00000000E+00,  1.10830937E+03, -2.26727390E+03,  3.38489942E+04, -1.46930038E+04, -7.18236724E+03,  0.00000000E+00, -1.10830937E+03,  2.26727390E+03, -1.59640788E+04,  2.60293733E+04,  1.27239141E+04,
    -1.10830937E+04,  0.00000000E+00,  1.54883268E+03, -1.46930038E+04,  1.33094132E+05, -1.05139787E+05,  1.10830937E+04,  0.00000000E+00, -1.54883268E+03,  1.00465058E+04, -3.00073581E+04,  7.18905057E+04,
     9.48650167E+03, -6.48047147E+02,  0.00000000E+00, -7.18236724E+03, -1.05139787E+05,  9.49823651E+04, -9.48650167E+03,  6.48047147E+02,  0.00000000E+00,  7.01895769E+02,  1.02747700E+04, -6.97630958E+04,
    -1.00000000E+03,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  1.10830937E+04, -9.48650167E+03,  1.00000000E+03,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -1.08309368E+03,  6.48650167E+03,
     0.00000000E+00, -1.00000000E+02,  0.00000000E+00, -1.10830937E+03,  0.00000000E+00,  6.48047147E+02,  0.00000000E+00,  1.00000000E+02,  0.00000000E+00,  1.08309368E+02,  0.00000000E+00, -1.14804715E+03,
     0.00000000E+00,  0.00000000E+00, -2.39000000E+02,  2.26727390E+03, -1.54883268E+03,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  2.39000000E+02, -1.55027390E+03,  2.74383268E+03,  0.00000000E+00,
     0.00000000E+00, -1.08309368E+02,  1.55027390E+03, -1.59640788E+04,  1.00465058E+04,  7.01895769E+02,  0.00000000E+00,  1.08309368E+02, -1.55027390E+03,  1.02301634E+04, -1.77978753E+04, -1.24344261E+03,
     1.08309368E+03,  0.00000000E+00, -2.74383268E+03,  2.60293733E+04, -3.00073581E+04,  1.02747700E+04, -1.08309368E+03,  0.00000000E+00,  2.74383268E+03, -1.77978753E+04,  3.28955848E+04, -7.02548896E+03,
    -6.48650167E+03,  1.14804715E+03,  0.00000000E+00,  1.27239141E+04,  7.18905057E+04, -6.97630958E+04,  6.48650167E+03, -1.14804715E+03,  0.00000000E+00, -1.24344261E+03, -7.02548896E+03,  5.60438265E+04
    });

    // Check
    ASSERT_TRUE (kgTarget == kgTest);
}

// 非重合节点：CID=0 + OCID>0(Si 偏置，球坐标系)
TEST_F (BushCalculatorTest, ComputeStiffnessWithTwoGridsCIDeq0SOCIDgt0)
{
    // Input data
    element.m_coordId = 0;
    element.m_oCId    = 301;
    element.m_s1      = 1.0;
    element.m_s2      = 2.0;
    element.m_s3      = 3.0;

    const Real* K{property.m_K};

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kgTest (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kgTest);
    kgTest = TEleOffset.Transpose () * kgTest * TEleOffset;

    // Target data
    const Matrixd kgTarget (n, n, {
     1.00000000E+03,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -8.87443878E+03,  9.59892118E+03, -1.00000000E+03,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -1.12556122E+03, -6.59892118E+03,
     0.00000000E+00,  1.00000000E+02,  0.00000000E+00,  8.87443878E+02,  0.00000000E+00, -6.27293331E+02,  0.00000000E+00, -1.00000000E+02,  0.00000000E+00,  1.12556122E+02,  0.00000000E+00,  1.12729333E+03,
     0.00000000E+00,  0.00000000E+00,  2.39000000E+02, -2.29414216E+03,  1.49923106E+03,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -2.39000000E+02,  1.57714216E+03, -2.69423106E+03,  0.00000000E+00,
     0.00000000E+00,  8.87443878E+02, -2.29414216E+03,  2.99538562E+04, -1.43910008E+04, -5.56687626E+03,  0.00000000E+00, -8.87443878E+02,  2.29414216E+03, -1.41969909E+04,  2.58617116E+04,  1.00040957E+04,
    -8.87443878E+03,  0.00000000E+00,  1.49923106E+03, -1.43910008E+04,  8.83822402E+04, -8.51850384E+04,  8.87443878E+03,  0.00000000E+00, -1.49923106E+03,  9.89330760E+03, -7.13400766E+03,  5.85617220E+04,
     9.59892118E+03, -6.27293331E+02,  0.00000000E+00, -5.56687626E+03, -8.51850384E+04,  9.68632570E+04, -9.59892118E+03,  6.27293331E+02,  0.00000000E+00, -7.06057044E+02, -1.08041734E+04, -7.12029601E+04,
    -1.00000000E+03,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  8.87443878E+03, -9.59892118E+03,  1.00000000E+03,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  1.12556122E+03,  6.59892118E+03,
     0.00000000E+00, -1.00000000E+02,  0.00000000E+00, -8.87443878E+02,  0.00000000E+00,  6.27293331E+02,  0.00000000E+00,  1.00000000E+02,  0.00000000E+00, -1.12556122E+02,  0.00000000E+00, -1.12729333E+03,
     0.00000000E+00,  0.00000000E+00, -2.39000000E+02,  2.29414216E+03, -1.49923106E+03,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  2.39000000E+02, -1.57714216E+03,  2.69423106E+03,  0.00000000E+00,
     0.00000000E+00,  1.12556122E+02,  1.57714216E+03, -1.41969909E+04,  9.89330760E+03, -7.06057044E+02,  0.00000000E+00, -1.12556122E+02, -1.57714216E+03,  1.05911256E+04, -1.77790184E+04,  1.26883765E+03,
    -1.12556122E+03,  0.00000000E+00, -2.69423106E+03,  2.58617116E+04, -7.13400766E+03, -1.08041734E+04,  1.12556122E+03,  0.00000000E+00,  2.69423106E+03, -1.77790184E+04,  3.18607751E+04,  7.42748974E+03,
    -6.59892118E+03,  1.12729333E+03,  0.00000000E+00,  1.00040957E+04,  5.85617220E+04, -7.12029601E+04,  6.59892118E+03, -1.12729333E+03,  0.00000000E+00,  1.26883765E+03,  7.42748974E+03,  5.70426633E+04
    });

    // Check
    ASSERT_TRUE (kgTarget == kgTest);
}

// 重合节点：CID>0(直角坐标系) + OCID=-1(S 偏置)
TEST_F (BushCalculatorTest, ComputeStiffnessWithCoincidentGridsRCIDgt0OCIDlt0)
{
    // Input data
    nodeSet[1] = {8, 0, {10.0, 13.0, 15.0}, 0};

    element.m_coordId = 100;

    const Real* K{property.m_K};

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kgTest (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kgTest);
    kgTest = TEleOffset.Transpose () * kgTest * TEleOffset;

    // Target data
    const Matrixd kgTarget (n, n, {
     7.03679739E+02, -3.80875817E+02, -1.48535948E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -7.03679739E+02,  3.80875817E+02,  1.48535948E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
    -3.80875817E+02,  4.50013072E+02,  2.05751634E+01,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  3.80875817E+02, -4.50013072E+02, -2.05751634E+01,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
    -1.48535948E+02,  2.05751634E+01,  1.85307190E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  1.48535948E+02, -2.05751634E+01, -1.85307190E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  1.77156863E+02,  2.01490196E+02, -1.04431373E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -1.77156863E+02, -2.01490196E+02,  1.04431373E+02,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  2.01490196E+02,  4.21156863E+02, -2.67098039E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -2.01490196E+02, -4.21156863E+02,  2.67098039E+02,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -1.04431373E+02, -2.67098039E+02,  4.69686275E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  1.04431373E+02,  2.67098039E+02, -4.69686275E+02,
    -7.03679739E+02,  3.80875817E+02,  1.48535948E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  7.03679739E+02, -3.80875817E+02, -1.48535948E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     3.80875817E+02, -4.50013072E+02, -2.05751634E+01,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -3.80875817E+02,  4.50013072E+02,  2.05751634E+01,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     1.48535948E+02, -2.05751634E+01, -1.85307190E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -1.48535948E+02,  2.05751634E+01,  1.85307190E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -1.77156863E+02, -2.01490196E+02,  1.04431373E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  1.77156863E+02,  2.01490196E+02, -1.04431373E+02,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -2.01490196E+02, -4.21156863E+02,  2.67098039E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  2.01490196E+02,  4.21156863E+02, -2.67098039E+02,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  1.04431373E+02,  2.67098039E+02, -4.69686275E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -1.04431373E+02, -2.67098039E+02,  4.69686275E+02
    });

    // Check
    ASSERT_TRUE (kgTarget == kgTest);
}

// 重合节点：CID=0 + OCID>0(Si 偏置，直角坐标系)
TEST_F (BushCalculatorTest, ComputeStiffnessWithCoincidentGridsCIDeq0ROCIDgt0)
{
    // Input data
    nodeSet[1] = {8, 0, {10.0, 13.0, 15.0}, 0};

    element.m_coordId = 0;
    element.m_oCId    = 101;
    element.m_s1      = 1.0;
    element.m_s2      = 2.0;
    element.m_s3      = 3.0;

    const Real* K{property.m_K};

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kgTest (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kgTest);
    kgTest = TEleOffset.Transpose () * kgTest * TEleOffset;

    // Target data
    const Matrixd kgTarget (n, n, {
     1.00000000E+03,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -1.10022289E+04,  1.04610925E+04, -1.00000000E+03,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  1.10022289E+04, -1.04610925E+04,
     0.00000000E+00,  1.00000000E+02,  0.00000000E+00,  1.10022289E+03,  0.00000000E+00, -8.18495205E+02,  0.00000000E+00, -1.00000000E+02,  0.00000000E+00, -1.10022289E+03,  0.00000000E+00,  8.18495205E+02,
     0.00000000E+00,  0.00000000E+00,  2.39000000E+02, -2.50020110E+03,  1.95620354E+03,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -2.39000000E+02,  2.50020110E+03, -1.95620354E+03,  0.00000000E+00,
     0.00000000E+00,  1.10022289E+03, -2.50020110E+03,  3.83167390E+04, -2.04640261E+04, -9.00527158E+03,  0.00000000E+00, -1.10022289E+03,  2.50020110E+03, -3.83167390E+04,  2.04640261E+04,  9.00527158E+03,
    -1.10022289E+04,  0.00000000E+00,  1.95620354E+03, -2.04640261E+04,  1.37282473E+05, -1.15095334E+05,  1.10022289E+04,  0.00000000E+00, -1.95620354E+03,  2.04640261E+04, -1.37282473E+05,  1.15095334E+05,
     1.04610925E+04, -8.18495205E+02,  0.00000000E+00, -9.00527158E+03, -1.15095334E+05,  1.16922800E+05, -1.04610925E+04,  8.18495205E+02,  0.00000000E+00,  9.00527158E+03,  1.15095334E+05, -1.16922800E+05,
    -1.00000000E+03,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  1.10022289E+04, -1.04610925E+04,  1.00000000E+03,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -1.10022289E+04,  1.04610925E+04,
     0.00000000E+00, -1.00000000E+02,  0.00000000E+00, -1.10022289E+03,  0.00000000E+00,  8.18495205E+02,  0.00000000E+00,  1.00000000E+02,  0.00000000E+00,  1.10022289E+03,  0.00000000E+00, -8.18495205E+02,
     0.00000000E+00,  0.00000000E+00, -2.39000000E+02,  2.50020110E+03, -1.95620354E+03,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  2.39000000E+02, -2.50020110E+03,  1.95620354E+03,  0.00000000E+00,
     0.00000000E+00, -1.10022289E+03,  2.50020110E+03, -3.83167390E+04,  2.04640261E+04,  9.00527158E+03,  0.00000000E+00,  1.10022289E+03, -2.50020110E+03,  3.83167390E+04, -2.04640261E+04, -9.00527158E+03,
     1.10022289E+04,  0.00000000E+00, -1.95620354E+03,  2.04640261E+04, -1.37282473E+05,  1.15095334E+05, -1.10022289E+04,  0.00000000E+00,  1.95620354E+03, -2.04640261E+04,  1.37282473E+05, -1.15095334E+05,
    -1.04610925E+04,  8.18495205E+02,  0.00000000E+00,  9.00527158E+03,  1.15095334E+05, -1.16922800E+05,  1.04610925E+04, -8.18495205E+02,  0.00000000E+00, -9.00527158E+03, -1.15095334E+05,  1.16922800E+05
    });

    // Check
    ASSERT_TRUE (kgTarget == kgTest);
}

// 单节点：CID>0(直角坐标系) + OCID=-1
TEST_F (BushCalculatorTest, ComputeStiffnessWithOneGridRCIDgt0OCIDlt0)
{
    // Input data
    nEleNodes = 1;
    element.m_g[1] = 0;
    element.m_coordId = 100;

    const Real* K{property.m_K};

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kgTest (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kgTest);
    kgTest = TEleOffset.Transpose () * kgTest * TEleOffset;

    // Target data
    const Matrixd kgTarget (n, n, {
     7.03679739E+02, -3.80875817E+02, -1.48535948E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
    -3.80875817E+02,  4.50013072E+02,  2.05751634E+01,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
    -1.48535948E+02,  2.05751634E+01,  1.85307190E+02,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  1.77156863E+02,  2.01490196E+02, -1.04431373E+02,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  2.01490196E+02,  4.21156863E+02, -2.67098039E+02,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -1.04431373E+02, -2.67098039E+02,  4.69686275E+02
    });

    // Check
    ASSERT_TRUE (kgTarget == kgTest);
}

// 单节点：CID=0 + OCID>0(直角坐标系)
TEST_F (BushCalculatorTest, ComputeStiffnessWithOneGridsCIDeq0ROCIDgt0)
{
    // Input data
    nEleNodes = 1;
    element.m_g[1]    = 0;
    element.m_coordId = 0;
    element.m_oCId    = 101;
    element.m_s1      = 1.0;
    element.m_s2      = 2.0;
    element.m_s3      = 3.0;

    const Real* K{property.m_K};

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kgTest (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kgTest);
    kgTest = TEleOffset.Transpose () * kgTest * TEleOffset;

    // Target data
    Matrixd kgTarget (n, n);
    kgTarget (0, 0) = property.m_K[0];
    kgTarget (1, 1) = property.m_K[1];
    kgTarget (2, 2) = property.m_K[2];
    kgTarget (3, 3) = property.m_K[3];
    kgTarget (4, 4) = property.m_K[4];
    kgTarget (5, 5) = property.m_K[5];

    // Check
    ASSERT_TRUE (kgTarget == kgTest);
}

// 局部坐标系单元质量矩阵：单节点
TEST_F (BushCalculatorTest, ComputeLocalMassWithOneGrid)
{
    // Input data
    nEleNodes = 1;

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd lumpedMTest (n, n);
    BushCalculator::ComputeMass (nEleNodes, element, nodeSet, property, lumpedMTest);

    // Target data
    Matrixd lumpedMTarget (n, n);
    lumpedMTarget (0, 0) = lumpedMTarget (1, 1) = lumpedMTarget (2, 2) = 10.0;

    // Check
    ASSERT_TRUE (lumpedMTarget == lumpedMTest);
}

// 局部坐标系单元质量矩阵：两节点
TEST_F (BushCalculatorTest, ComputeLocalMassWithTwoGrids)
{
    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd lumpedMTest (n, n);
    BushCalculator::ComputeMass (nEleNodes, element, nodeSet, property, lumpedMTest);

    // Target data
    Matrixd lumpedMTarget (n, n);
    lumpedMTarget (0, 0) = lumpedMTarget (1, 1) = lumpedMTarget (2, 2) = 5.0;
    lumpedMTarget (6, 6) = lumpedMTarget (7, 7) = lumpedMTarget (8, 8) = 5.0;

    // Check
    ASSERT_TRUE (lumpedMTarget == lumpedMTest);
}

// 非重合节点：CID=0 + OCID=-1(S 偏置)
TEST_F (BushCalculatorTest, DataRecoveryWithTwoGridsCIDeq0OCIDlt0)
{
    // Input data
    element.m_coordId = 0;

    const Real* K{property.m_K};

    const std::size_t n{6 * nEleNodes};

    const Matrixd eleDisplacement (n, 1, {
    0.0,                 0.0,                0.0,                0.0,                 0.0,                0.0,
    251.74504161956645,  789.3782936428524, -92.88866602784235,  149.12280701754386, -47.29729729729731,  9.505703422053259
    });

    // Test data
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kl (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kl);
    Matrixd eleInternalForceTest (6, 1);
    BushCalculator::ComputeElementInternalForce (nEleNodes, kl, TEleOffset, eleDisplacement, _OUT eleInternalForceTest);
    Matrixd eleStrainTest (6, 1);
    BushCalculator::ComputeElementStrain (property, nEleNodes, TEleOffset, eleDisplacement, _OUT eleStrainTest);
    Matrixd eleStressTest (6, 1);
    BushCalculator::ComputeElementStress (eleInternalForceTest, property, _OUT eleStressTest);

    // Target data
    const Matrixd eleInternalForceTarget (6, 1, {1.000000E+03,  2.000000E+03,  3.000000E+03,  8.500000E+03, -1.050000E+04,  7.500000E+03});
    const Matrixd eleStrainTarget (6, 1, {1.000000E+00,  2.000000E+01,  1.255230E+01,  1.491228E+02, -4.729730E+01,  9.505703E+00});
    const Matrixd eleStressTarget (6, 1, {1.000000E+03,  2.000000E+03,  3.000000E+03,  8.500000E+03, -1.050000E+04,  7.500000E+03});

    // Check
    ASSERT_TRUE (eleInternalForceTarget == eleInternalForceTest);
    ASSERT_TRUE (eleStrainTarget == eleStrainTest);
    ASSERT_TRUE (eleStressTarget == eleStressTest);
}

// 非重合节点：CID>0(直角坐标系) + OCID=0(Si 偏置)
TEST_F (BushCalculatorTest, ComputeElementInternalForceStrainStressWithTwoGridsRCIDgt0OCIDeq0)
{
    // Input data
    element.m_coordId = 100;
    element.m_oCId    = 0;
    element.m_s1      = 1.0;
    element.m_s2      = 2.0;
    element.m_s3      = 3.0;

    const Real* K{property.m_K};

    const std::size_t n{6 * nEleNodes};

    const Matrixd eleDisplacement (n, 1, {
     0.0,                0.0,                0.0,                0.0,                0.0,                0.0,
    -321.8036468851921, -1747.995862376456,  9456.539133306904,  524.6921809093898, -373.6764699106619, -51.12759111629224
    });

    // Test data
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kl (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kl);
    Matrixd eleInternalForceTest (6, 1);
    BushCalculator::ComputeElementInternalForce (nEleNodes, kl, TEleOffset, eleDisplacement, _OUT eleInternalForceTest);
    Matrixd eleStrainTest (6, 1);
    BushCalculator::ComputeElementStrain (property, nEleNodes, TEleOffset, eleDisplacement, _OUT eleStrainTest);
    Matrixd eleStressTest (6, 1);
    BushCalculator::ComputeElementStress (eleInternalForceTest, property, _OUT eleStressTest);

    // Target data
    const Matrixd eleInternalForceTarget (6, 1, {-8.084521E+02, -3.638034E+03, -3.333333E+02,  3.670372E+04, -8.003676E+03, -3.166667E+04});
    const Matrixd eleStrainTarget (6, 1, {-8.084521E-01, -3.638034E+01, -1.394700E+00,  6.439250E+02, -3.605259E+01, -4.013519E+01});
    const Matrixd eleStressTarget (6, 1, {-8.084521E+02, -3.638034E+03, -3.333333E+02,  3.670372E+04, -8.003676E+03, -3.166667E+04});

    // Check
    ASSERT_TRUE (eleInternalForceTarget == eleInternalForceTest);
    ASSERT_TRUE (eleStrainTarget == eleStrainTest);
    ASSERT_TRUE (eleStressTarget == eleStressTest);
}
TEST_F (BushCalculatorTest, ComputeMassWithTwoGridsRCIDgt0OCIDeq0)
{
    // Input data
    element.m_coordId = 100;
    element.m_oCId    = 0;
    element.m_s1      = 1.0;
    element.m_s2      = 2.0;
    element.m_s3      = 3.0;

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd lumpedMTest (n, n);
    BushCalculator::ComputeMass (nEleNodes, element, nodeSet, property, lumpedMTest);

    // Target data
    Matrixd lumpedMTarget (n, n);
    lumpedMTarget (0, 0) = lumpedMTarget (1, 1) = lumpedMTarget (2, 2) = 4.66240234;
    lumpedMTarget (6, 6) = lumpedMTarget (7, 7) = lumpedMTarget (8, 8) = 5.33759766;

    // Check
    ASSERT_TRUE (lumpedMTarget == lumpedMTest);
}

// 非重合节点：朝向矢量 + OCID=-1(S 偏置)
TEST_F (BushCalculatorTest, ComputeElementInternalForceStrainStressWithTwoGridsOrienVectorOCIDlt0)
{
    // Input data
    element.m_x1 = -10.0;
    element.m_x2 = -12.0;
    element.m_x3 = -13.0;

    const Real* K{property.m_K};

    const std::size_t n{6 * nEleNodes};

    const Matrixd eleDisplacement (n, 1, {
    0.0,                0.0,                 0.0,                  0.0,                 0.0,                0.0,
    77.63886701217466,  139.39672747545694,  0.10041526345023932,  18.421013737681587, -7.526103671008208,  13.222723935055628
    });

    // Test data
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kl (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kl);
    Matrixd eleInternalForceTest (6, 1);
    BushCalculator::ComputeElementInternalForce (nEleNodes, kl, TEleOffset, eleDisplacement, _OUT eleInternalForceTest);
    Matrixd eleStrainTest (6, 1);
    BushCalculator::ComputeElementStrain (property, nEleNodes, TEleOffset, eleDisplacement, _OUT eleStrainTest);
    Matrixd eleStressTest (6, 1);
    BushCalculator::ComputeElementStress (eleInternalForceTest, property, _OUT eleStressTest);

    // Target data
    const Matrixd eleInternalForceTarget (6, 1, {-2.677992E+03, -2.611097E+03, -1.026089E+02, -8.638684E+01, -3.146740E+03, -1.512748E+04});
    const Matrixd eleStrainTarget (6, 1, {-2.677992E+00, -2.611097E+01, -4.293258E-01, -1.515559E+00, -1.417450E+01, -1.917297E+01});
    const Matrixd eleStressTarget (6, 1, {-2.677992E+03, -2.611097E+03, -1.026089E+02, -8.638684E+01, -3.146740E+03, -1.512748E+04});

    // Check
    ASSERT_TRUE (eleInternalForceTarget == eleInternalForceTest);
    ASSERT_TRUE (eleStrainTarget == eleStrainTest);
    ASSERT_TRUE (eleStressTarget == eleStressTest);
}

// 非重合节点：朝向节点 + OCID>0(Si 偏置，直角坐标系)
TEST_F (BushCalculatorTest, ComputeElementInternalForceStrainStressWithTwoGridsGOROCIDgt0)
{
    // Input data
    element.m_go   = 9;
    element.m_oCId = 101;
    element.m_s1   = 1.0;
    element.m_s2   = 2.0;
    element.m_s3   = 3.0;

    const Real* K{property.m_K};

    const std::size_t n{6 * nEleNodes};

    const Matrixd eleDisplacement (n, 1, {
    0.0,                0.0,                 0.0,                 0.0,                 0.0,                0.0,
    5.840677151286794, -104.77865694477836,  1083.4800087284223,  57.846771691214144, -48.76492663976748, -4.629353228290391
    });

    // Test data
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kl (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kl);
    Matrixd eleInternalForceTest (6, 1);
    BushCalculator::ComputeElementInternalForce (nEleNodes, kl, TEleOffset, eleDisplacement, _OUT eleInternalForceTest);
    Matrixd eleStrainTest (6, 1);
    BushCalculator::ComputeElementStrain (property, nEleNodes, TEleOffset, eleDisplacement, _OUT eleStrainTest);
    Matrixd eleStressTest (6, 1);
    BushCalculator::ComputeElementStress (eleInternalForceTest, property, _OUT eleStressTest);

    // Target data
    const Matrixd eleInternalForceTarget (6, 1, {-2.677992E+03, -2.611097E+03, -1.026089E+02,  2.372516E+03, -4.397395E+03, -4.747693E+04});
    const Matrixd eleStrainTarget (6, 1, {-2.677992E+00, -2.611097E+01, -4.293258E-01,  4.162310E+01, -1.980809E+01, -6.017355E+01});
    const Matrixd eleStressTarget (6, 1, {-2.677992E+03, -2.611097E+03, -1.026089E+02,  2.372516E+03, -4.397395E+03, -4.747693E+04});

    // Check
    ASSERT_TRUE (eleInternalForceTarget == eleInternalForceTest);
    ASSERT_TRUE (eleStrainTarget == eleStrainTest);
    ASSERT_TRUE (eleStressTarget == eleStressTest);
}
TEST_F (BushCalculatorTest, ComputeMassWithTwoGridsGOROCIDgt0)
{
    // Input data
    element.m_go   = 9;
    element.m_oCId = 101;
    element.m_s1   = 1.0;
    element.m_s2   = 2.0;
    element.m_s3   = 3.0;

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd lumpedMTest (n, n);
    BushCalculator::ComputeMass (nEleNodes, element, nodeSet, property, lumpedMTest);

    // Target data
    Matrixd lumpedMTarget (n, n);
    lumpedMTarget (0, 0) = lumpedMTarget (1, 1) = lumpedMTarget (2, 2) = 4.68165701;
    lumpedMTarget (6, 6) = lumpedMTarget (7, 7) = lumpedMTarget (8, 8) = 5.31834299;

    // Check
    ASSERT_TRUE (lumpedMTarget == lumpedMTest);
}

// 非重合节点：CID、朝向节点、朝向矢量均未指定，1、4 方向 Ki 至少一个不为 0.0，同时 2、3、5、6 方向的 Ki 必须为 0.0 + OCID=0(Si 偏置)
TEST_F (BushCalculatorTest, ComputeElementInternalForceStrainStressWithTwoGridsK4OCIDeq0)
{
    // Input data
    element.m_oCId = 0;
    element.m_s1   = 1.0;
    element.m_s2   = 2.0;
    element.m_s3   = 3.0;

    property.m_K[0] = 0.0;
    property.m_K[1] = 0.0;
    property.m_K[2] = 0.0;
    property.m_K[4] = 0.0;
    property.m_K[5] = 0.0;
    const Real* K{property.m_K};

    const std::size_t n{6 * nEleNodes};

    const Matrixd eleDisplacement (n, 1, {
    0.0,  0.0,  0.0,  0.0,  0.0,  0.0,
    0.0,  0.0,  0.0,  0.0,  0.0,  23.5087719298245
    });

    // Test data
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kl (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kl);
    Matrixd eleInternalForceTest (6, 1);
    BushCalculator::ComputeElementInternalForce (nEleNodes, kl, TEleOffset, eleDisplacement, _OUT eleInternalForceTest);
    Matrixd eleStrainTest (6, 1);
    BushCalculator::ComputeElementStrain (property, nEleNodes, TEleOffset, eleDisplacement, _OUT eleStrainTest);
    Matrixd eleStressTest (6, 1);
    BushCalculator::ComputeElementStress (eleInternalForceTest, property, _OUT eleStressTest);

    // Target data
    const Matrixd eleInternalForceTarget (6, 1, {0.0,  0.0,  0.0, -1.157584E+03,  0.0,  0.0});
    const Matrixd eleStrainTarget (6, 1, {1.665296E+02,  0.0,  0.0, -2.030849E+01,  0.0,  0.0});
    const Matrixd eleStressTarget (6, 1, {0.0,  0.0,  0.0, -1.157584E+03,  0.0,  0.0});

    // Check
    ASSERT_TRUE (eleInternalForceTarget == eleInternalForceTest);
    ASSERT_TRUE (eleStrainTarget == eleStrainTest);
    ASSERT_TRUE (eleStressTarget == eleStressTest);
}
TEST_F (BushCalculatorTest, ComputeMassWithTwoGridsK4OCIDeq0)
{
    // Input data
    element.m_oCId = 0;
    element.m_s1   = 1.0;
    element.m_s2   = 2.0;
    element.m_s3   = 3.0;

    property.m_K[0] = 0.0;
    property.m_K[1] = 0.0;
    property.m_K[2] = 0.0;
    property.m_K[4] = 0.0;
    property.m_K[5] = 0.0;
    const Real* K{property.m_K};

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd lumpedMTest (n, n);
    BushCalculator::ComputeMass (nEleNodes, element, nodeSet, property, lumpedMTest);
    lumpedMTest = TEle.Transpose () * lumpedMTest * TEle;

    // Target data
    const Matrixd lumpedMTarget (n, n, {
     8.69851183E-01, -5.21910710E-01, -1.73970237E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
    -5.21910710E-01,  3.13146426E-01,  1.04382142E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
    -1.73970237E+00,  1.04382142E+00,  3.47940473E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  9.95820459E-01, -5.97492275E-01, -1.99164092E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -5.97492275E-01,  3.58495365E-01,  1.19498455E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00, -1.99164092E+00,  1.19498455E+00,  3.98328183E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,
     0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00,  0.00000000E+00
    });

    // Check
    ASSERT_TRUE (lumpedMTarget == lumpedMTest);
}

// 非重合节点：节点定义球坐标系 + 位移输出球坐标系 + 朝向节点 + OCID=-1(S 偏置)
TEST_F (BushCalculatorTest, ComputeElementInternalForceStrainStressWithTwoGridsSCPSCDGOOCIDlt0)
{
    // Input data
    nodeSet[0].m_defCoord  = 300;
    nodeSet[0].m_dispCoord = 301;
    nodeSet[1].m_defCoord  = 301;
    nodeSet[1].m_dispCoord = 300;
    orienNode.m_defCoord   = 301;

    element.m_go = 9;

    const Real* K{property.m_K};

    const std::size_t n{6 * nEleNodes};

    const Matrixd eleDisplacement (n, 1, {
    0.0,                 0.0,                0.0,                 0.0,                 0.0,                 0.0,
    -9.898748009831529, -56.00871938300014,  120.55230985235849,  11.873442400196705, -59.214532512867336, -29.442303102080654
    });

    // Test data
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kl (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kl);
    Matrixd eleInternalForceTest (6, 1);
    BushCalculator::ComputeElementInternalForce (nEleNodes, kl, TEleOffset, eleDisplacement, _OUT eleInternalForceTest);
    Matrixd eleStrainTest (6, 1);
    BushCalculator::ComputeElementStrain (property, nEleNodes, TEleOffset, eleDisplacement, _OUT eleStrainTest);
    Matrixd eleStressTest (6, 1);
    BushCalculator::ComputeElementStress (eleInternalForceTest, property, _OUT eleStressTest);

    // Target data
    const Matrixd eleInternalForceTarget (6, 1, {-2.197294E+03,  1.349393E+03,  2.711280E+03, -3.018678E+03, -9.035699E+03,  5.738907E+03});
    const Matrixd eleStrainTarget (6, 1, {-2.197294E+00,  1.349393E+01,  1.134427E+01, -5.295926E+01, -4.070135E+01,  7.273646E+00});
    const Matrixd eleStressTarget (6, 1, {-2.197294E+03,  1.349393E+03,  2.711280E+03, -3.018678E+03, -9.035699E+03,  5.738907E+03});

    // Check
    ASSERT_TRUE (eleInternalForceTarget == eleInternalForceTest);
    ASSERT_TRUE (eleStrainTarget == eleStrainTest);
    ASSERT_TRUE (eleStressTarget == eleStressTest);
}
TEST_F (BushCalculatorTest, ComputeMassWithTwoGridsSCPSCDGOOCIDlt0)
{
    // Input data
    nodeSet[0].m_defCoord  = 300;
    nodeSet[0].m_dispCoord = 301;
    nodeSet[1].m_defCoord  = 301;
    nodeSet[1].m_dispCoord = 300;
    orienNode.m_defCoord   = 301;

    element.m_go = 9;

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd lumpedMTest (n, n);
    BushCalculator::ComputeMass (nEleNodes, element, nodeSet, property, lumpedMTest);

    // Target data
    Matrixd lumpedMTarget (n, n);
    lumpedMTarget (0, 0) = lumpedMTarget (1, 1) = lumpedMTarget (2, 2) = 5.0;
    lumpedMTarget (6, 6) = lumpedMTarget (7, 7) = lumpedMTarget (8, 8) = 5.0;

    // Check
    ASSERT_TRUE (lumpedMTarget == lumpedMTest);
}

// 非重合节点：CID>0(柱坐标系) + OCID>0(Si 偏置，柱坐标系)
TEST_F (BushCalculatorTest, ComputeElementInternalForceStrainStressWithTwoGridsCCPCCDCCIDgt0COCIDgt0)
{
    // Input data
    nodeSet[0].m_defCoord  = 200;
    nodeSet[0].m_dispCoord = 201;
    nodeSet[1].m_defCoord  = 201;
    nodeSet[1].m_dispCoord = 200;

    element.m_coordId = 200;
    element.m_oCId    = 201;
    element.m_s1      = 1.0;
    element.m_s2      = 2.0;
    element.m_s3      = 3.0;

    const Real* K{property.m_K};

    const std::size_t n{6 * nEleNodes};

    const Matrixd eleDisplacement (n, 1, {
    0.0,                 0.0,                0.0,                0.0,                0.0,                0.0,
    60.009774778677155, -512.5253625701749, -597.5639647136496, -60.06553465726029,  31.09880151354496, -32.60497932188281
    });

    // Test data
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kl (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kl);
    Matrixd eleInternalForceTest (6, 1);
    BushCalculator::ComputeElementInternalForce (nEleNodes, kl, TEleOffset, eleDisplacement, _OUT eleInternalForceTest);
    Matrixd eleStrainTest (6, 1);
    BushCalculator::ComputeElementStrain (property, nEleNodes, TEleOffset, eleDisplacement, _OUT eleStrainTest);
    Matrixd eleStressTest (6, 1);
    BushCalculator::ComputeElementStress (eleInternalForceTest, property, _OUT eleStressTest);

    // Target data
    const Matrixd eleInternalForceTarget (6, 1, {-1.606111E+03, -3.362930E+03, -3.333333E+02, -3.838388E+03, 1.409481E+03, -2.572533E+04});
    const Matrixd eleStrainTarget (6, 1, {-1.606111E+00, -3.362930E+01, -1.394700E+00, -6.734014E+01, 6.349016E+00, -3.260498E+01});
    const Matrixd eleStressTarget (6, 1, {-1.606111E+03, -3.362930E+03, -3.333333E+02, -3.838388E+03, 1.409481E+03, -2.572533E+04});

    // Check
    ASSERT_TRUE (eleInternalForceTarget == eleInternalForceTest);
    ASSERT_TRUE (eleStrainTarget == eleStrainTest);
    ASSERT_TRUE (eleStressTarget == eleStressTest);
}
TEST_F (BushCalculatorTest, ComputeMassWithTwoGridsCCPCCDCCIDgt0COCIDgt0)
{
    // Input data
    nodeSet[0].m_defCoord  = 200;
    nodeSet[0].m_dispCoord = 201;
    nodeSet[1].m_defCoord  = 201;
    nodeSet[1].m_dispCoord = 200;

    element.m_coordId = 200;
    element.m_oCId    = 201;
    element.m_s1      = 1.0;
    element.m_s2      = 2.0;
    element.m_s3      = 3.0;

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd lumpedMTest (n, n);
    BushCalculator::ComputeMass (nEleNodes, element, nodeSet, property, lumpedMTest);

    // Target data
    Matrixd lumpedMTarget (n, n);
    lumpedMTarget (0, 0) = lumpedMTarget (1, 1) = lumpedMTarget (2, 2) = 4.54278870;
    lumpedMTarget (6, 6) = lumpedMTarget (7, 7) = lumpedMTarget (8, 8) = 5.45721130;

    // Check
    ASSERT_TRUE (lumpedMTarget == lumpedMTest);
}

// 重合节点：CID>0(球坐标系) + OCID>0(Si 偏置，球坐标系)
TEST_F (BushCalculatorTest, ComputeElementInternalForceStrainStressWithCoincidentGridsCCPCCDCCIDgt0COCIDgt0)
{
    // Input data
    nodeSet[0].m_defCoord  = 200;
    nodeSet[0].m_dispCoord = 201;
    nodeSet[1] = {8, 200, {10.0, 13.0, 15.0}, 200};

    element.m_coordId = 200;
    element.m_oCId    = 201;
    element.m_s1      = 1.0;
    element.m_s2      = 2.0;
    element.m_s3      = 3.0;

    const Real* K{property.m_K};

    const std::size_t n{6 * nEleNodes};

    const Matrixd eleDisplacement (n, 1, {
     0.0,                 0.0,                 0.0,                0.0,                0.0,                 0.0,
    -1287.8839159027432, -11395.757162467973,  3196.470358183901,  802.5645094592816, -100.16186289539907, -33.062989279846825
    });

    // Test data
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kl (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kl);
    Matrixd eleInternalForceTest (6, 1);
    BushCalculator::ComputeElementInternalForce (nEleNodes, kl, TEleOffset, eleDisplacement, _OUT eleInternalForceTest);
    Matrixd eleStrainTest (6, 1);
    BushCalculator::ComputeElementStrain (property, nEleNodes, TEleOffset, eleDisplacement, _OUT eleStrainTest);
    Matrixd eleStressTest (6, 1);
    BushCalculator::ComputeElementStress (eleInternalForceTest, property, _OUT eleStressTest);

    // Target data
    const Matrixd eleInternalForceTarget (6, 1, {-1.606111E+03, -3.362930E+03, -3.333333E+02,  4.574618E+04, -2.223593E+04, -2.608670E+04});
    const Matrixd eleStrainTarget (6, 1, {-1.606111E+00, -3.362930E+01, -1.394700E+00,  8.025645E+02, -1.001619E+02, -3.306299E+01});
    const Matrixd eleStressTarget (6, 1, {-1.606111E+03, -3.362930E+03, -3.333333E+02,  4.574618E+04, -2.223593E+04, -2.608670E+04});

    // Check
    ASSERT_TRUE (eleInternalForceTarget == eleInternalForceTest);
    ASSERT_TRUE (eleStrainTarget == eleStrainTest);
    ASSERT_TRUE (eleStressTarget == eleStressTest);
}
TEST_F (BushCalculatorTest, ComputeMassWithCoincidentGridsCCPCCDCCIDgt0COCIDgt0)
{
    // Input data
    nodeSet[0].m_defCoord  = 200;
    nodeSet[0].m_dispCoord = 201;
    nodeSet[1] = {8, 200, {10.0, 13.0, 15.0}, 200};

    element.m_coordId = 200;
    element.m_oCId    = 201;
    element.m_s1      = 1.0;
    element.m_s2      = 2.0;
    element.m_s3      = 3.0;

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd lumpedMTest (n, n);
    BushCalculator::ComputeMass (nEleNodes, element, nodeSet, property, lumpedMTest);

    // Target data
    Matrixd lumpedMTarget (n, n);
    lumpedMTarget (0, 0) = lumpedMTarget (1, 1) = lumpedMTarget (2, 2) = 5.0;
    lumpedMTarget (6, 6) = lumpedMTarget (7, 7) = lumpedMTarget (8, 8) = 5.0;

    // Check
    ASSERT_TRUE (lumpedMTarget == lumpedMTest);
}

// 单节点：CID>0(直角坐标系) + OCID=-1
TEST_F (BushCalculatorTest, ComputeElementInternalForceStrainStressWithOneGridRCIDgt0OCIDlt0)
{
    // Input data
    nEleNodes = 1;
    element.m_g[1] = 0;
    element.m_coordId = 100;

    const Real* K{property.m_K};

    const std::size_t n{6 * nEleNodes};

    const Matrixd eleDisplacement (n, 1, {
    16.528564005797588,  17.174775070418693,  27.531107282522505,  23.64657327046526, -2.9397488932033218,  5.714969934678232
    });

    // Test data
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kl (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kl);
    Matrixd eleInternalForceTest (6, 1);
    BushCalculator::ComputeElementInternalForce (nEleNodes, kl, TEleOffset, eleDisplacement, _OUT eleInternalForceTest);
    Matrixd eleStrainTest (6, 1);
    BushCalculator::ComputeElementStrain (property, nEleNodes, TEleOffset, eleDisplacement, _OUT eleStrainTest);
    Matrixd eleStressTest (6, 1);
    BushCalculator::ComputeElementStress (eleInternalForceTest, property, _OUT eleStressTest);

    // Target data
    const Matrixd eleInternalForceTarget (6, 1, {-8.084521E+02, -3.638034E+03, -3.333333E+02,  1.131833E+03, -3.152963E+03,  1.666667E+03});
    const Matrixd eleStrainTarget (6, 1, {-8.084521E-01, -3.638034E+01, -1.394700E+00,  1.985672E+01, -1.420254E+01,  2.112379E+00});
    const Matrixd eleStressTarget (6, 1, {-8.084521E+02, -3.638034E+03, -3.333333E+02,  1.131833E+03, -3.152963E+03,  1.666667E+03});

    // Check
    ASSERT_TRUE (eleInternalForceTarget == eleInternalForceTest);
    ASSERT_TRUE (eleStrainTarget == eleStrainTest);
    ASSERT_TRUE (eleStressTarget == eleStressTest);
}
TEST_F (BushCalculatorTest, ComputeMassWithOneGridRCIDgt0OCIDlt0)
{
    // Input data
    nEleNodes = 1;
    element.m_g[1] = 0;
    element.m_coordId = 100;

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd lumpedMTest (n, n);
    BushCalculator::ComputeMass (nEleNodes, element, nodeSet, property, lumpedMTest);

    // Target data
    Matrixd lumpedMTarget (n, n);
    lumpedMTarget (0, 0) = lumpedMTarget (1, 1) = lumpedMTarget (2, 2) = 10.0;

    // Check
    ASSERT_TRUE (lumpedMTarget == lumpedMTest);
}

// 单节点：CID=0 + OCID>0(直角坐标系)
TEST_F (BushCalculatorTest, ComputeElementInternalForceStrainStressWithOneGridsCIDeq0ROCIDgt0)
{
    // Input data
    nEleNodes = 1;
    element.m_g[1]    = 0;
    element.m_coordId = 0;
    element.m_oCId    = 101;
    element.m_s1      = 1.0;
    element.m_s2      = 2.0;
    element.m_s3      = 3.0;

    const Real* K{property.m_K};

    const std::size_t n{6 * nEleNodes};

    const Matrixd eleDisplacement (n, 1, {
    1.0,  20.0,  12.552301255230125,  52.63157894736842,  9.00900900900901,  1.2674271229404308
    });

    // Test data
    Matrixd TEle (n, n);
    Matrixd TEleOffset (n, n);
    BushCalculator::ComputeElementTrans (nEleNodes, element, nodeSet, orienNode, K, _OUT isSpecifyEleCoordSys, _OUT TEle, _OUT TEleOffset);
    Matrixd kl (n, n);
    BushCalculator::ComputeStiffness (nEleNodes, property, _OUT kl);
    Matrixd eleInternalForceTest (6, 1);
    BushCalculator::ComputeElementInternalForce (nEleNodes, kl, TEleOffset, eleDisplacement, _OUT eleInternalForceTest);
    Matrixd eleStrainTest (6, 1);
    BushCalculator::ComputeElementStrain (property, nEleNodes, TEleOffset, eleDisplacement, _OUT eleStrainTest);
    Matrixd eleStressTest (6, 1);
    BushCalculator::ComputeElementStress (eleInternalForceTest, property, _OUT eleStressTest);

    // Target data
    const Matrixd eleInternalForceTarget (6, 1, {1.000000E+03,  2.000000E+03,  3.000000E+03,  3.000000E+03,  2.000000E+03,  1.000000E+03});
    const Matrixd eleStrainTarget (6, 1, {1.000000E+00,  2.000000E+01,  1.255230E+01,  5.263158E+01,  9.009009E+00,  1.267427E+00});
    const Matrixd eleStressTarget (6, 1, {1.000000E+03,  2.000000E+03,  3.000000E+03,  3.000000E+03,  2.000000E+03,  1.000000E+03});

    // Check
    ASSERT_TRUE (eleInternalForceTarget == eleInternalForceTest);
    ASSERT_TRUE (eleStrainTarget == eleStrainTest);
    ASSERT_TRUE (eleStressTarget == eleStressTest);
}
TEST_F (BushCalculatorTest, ComputeMassWithOneGridsCIDeq0ROCIDgt0)
{
    // Input data
    nEleNodes = 1;
    element.m_g[1]    = 0;
    element.m_coordId = 0;
    element.m_oCId    = 101;
    element.m_s1      = 1.0;
    element.m_s2      = 2.0;
    element.m_s3      = 3.0;

    // Test data
    const std::size_t n{6 * nEleNodes};
    Matrixd lumpedMTest (n, n);
    BushCalculator::ComputeMass (nEleNodes, element, nodeSet, property, lumpedMTest);

    // Target data
    Matrixd lumpedMTarget (n, n);
    lumpedMTarget (0, 0) = lumpedMTarget (1, 1) = lumpedMTarget (2, 2) = 10.0;

    // Check
    ASSERT_TRUE (lumpedMTarget == lumpedMTest);
}